/*********************************************************************************************************
 *  ------------------------------------------------------------------------------------------------------
 *  file description
 *  ------------------------------------------------------------------------------------------------------
 *         \file  slup.c
 *         \unit  slup
 *        \brief  This is a simple serial link universal protocol for C language
 *       \author  Lamdonn
 *      \version  v0.1.0
 *      \license  GPL-2.0
 *    \copyright  Copyright (C) 2023 Lamdonn.
 ********************************************************************************************************/
#include "slup.h"

/*
| HEAD | SN | FrameType | Length | Data | Check | TAIL |
*/

// Macro to send a character and perform some additional operations.
// It calls the putc function pointer in the slup structure to send the character 'c'.
// It also logs the character in hexadecimal format using SLUP_DEBUG and updates the upload statistics.
#define sputc(c)                            do { (slup->putc)(c); SLUP_DEBUG("%02x ", (c)); slup_statis_upload(slup); } while (0) 

// Macro to access the i-th element of the head mask in the SLUP configuration.
#define head(i)                             (slup->cfg.head[(i)])  

// Macro to access the i-th element of the tail mask in the SLUP configuration.
#define tail(i)                             (slup->cfg.tail[(i)])    

// Macro to access the i-th byte of the sequence number (sn) in the slup structure.
#define sn(i)                               (((uint8_t *)(&(slup->sn)))[(i)])

// Macro to access the i-th byte of the length variable.
#define len(i)                              (((uint8_t *)(&(length)))[(i)])

// Define states for the SLUP receive state machine.
#define SLUP_RX_STATE_HEAD                  0
#define SLUP_RX_STATE_SN                    1
#define SLUP_RX_STATE_FRAMETYPE             2
#define SLUP_RX_STATE_LENGTH                3
#define SLUP_RX_STATE_DATA                  4
#define SLUP_RX_STATE_CHECK                 5
#define SLUP_RX_STATE_TAIL                  6

// Debug macro, currently defined as an empty operation.
// Can be redefined to use printf for debugging purposes.
#define SLUP_DEBUG(...)
// #define SLUP_DEBUG                          printf

/**
 * \brief Pushes a character into the SLUP queue.
 * \param queue: Pointer to the SLUP queue structure.
 * \param data: The character to be pushed into the queue.
 * \return 1 if the push operation is successful, 0 otherwise.
 * 
 * This function adds a character to the SLUP queue. If the queue is not full,
 * it simply adds the character to the tail of the queue and updates the tail index and size.
 * If the queue is full, it overwrites the oldest element and updates both the head and tail indices.
 */
static int slup_queue_push(SLUP_QUEUE *queue, char data)
{
    if (!queue) return 0;

    if (queue->size < SLUP_RXQUE_SIZE) 
    {
        queue->base[queue->tail] = data;
        queue->tail = (queue->tail + 1) % SLUP_RXQUE_SIZE;
        queue->size++;
    }
    else 
    {
        queue->base[queue->tail] = data;
        queue->tail = (queue->tail + 1) % SLUP_RXQUE_SIZE;
        queue->head = (queue->head + 1) % SLUP_RXQUE_SIZE;
    }
    
    return 1;
}

/**
 * \brief Pops a specified number of elements from the SLUP queue.
 * \param queue: Pointer to the SLUP queue structure.
 * \param count: The number of elements to be popped from the queue.
 * \return 1 if the pop operation is successful, 0 otherwise.
 * 
 * This function removes a specified number of elements from the SLUP queue.
 * If the number of elements to be popped is greater than the current size of the queue,
 * it will only pop the existing elements in the queue.
 */
static int slup_queue_pop(SLUP_QUEUE *queue, uint32_t count)
{
    if (!queue) return 0;
    if (queue->size == 0) return 0;
    if (count == 0) return 0;
    
    if (count > queue->size) count = queue->size;

    queue->head = (queue->head + count) % SLUP_RXQUE_SIZE;
    queue->size -= count;
    
    return 1;
}

/**
 * \brief Retrieves an element at a specified index from the SLUP queue.
 * \param queue: Pointer to the SLUP queue structure.
 * \param index: The index of the element to be retrieved.
 * \return The character at the specified index if the queue is valid and not empty, 0 otherwise.
 * 
 * This function returns the element at a given index in the SLUP queue.
 * The index is calculated relative to the head of the queue.
 */
static char slup_queue_at(SLUP_QUEUE *queue, uint32_t index)
{
    if (!queue) return 0;
    if (queue->size == 0) return 0;
    return queue->base[((queue->head + index) % SLUP_RXQUE_SIZE)];
}

/**
 * \brief Update the upload statistics of the SLUP structure.
 * \param slup: Pointer to the SLUP structure.
 * 
 * This function increments the 'upbits' field in the SLUP structure by 8,
 * indicating that 8 bits of data have been uploaded. It is called within the 'sputc' macro
 * when sending data to keep track of the amount of uploaded data.
 */
static void slup_statis_upload(SLUP *slup)
{
    slup->upbits += 8;
}

/**
 * \brief Update the download statistics of the SLUP structure.
 * \param slup: Pointer to the SLUP structure.
 * 
 * This function increments the 'downbits' field in the SLUP structure by 8,
 * indicating that 8 bits of data have been downloaded. It is used to track
 * the amount of data received in the SLUP communication process.
 */
static void slup_statis_download(SLUP *slup)
{
    slup->downbits += 8;
}

/**
 * \brief Receive and process an SLUP package.
 * \param slup: Pointer to the SLUP structure.
 * \return SLUP_E_OK: Indicates that the package has been successfully received and processed.
 * 
 * This function first checks the 'frame' field in the 'parser' of the SLUP structure.
 * If the 'frame' is 0x00, it extracts the link information from the first byte of the 'buffer'.
 * Depending on the result of the bitwise AND operation between the link information and SLUP_LINK_RX,
 * it updates the 'link' field in the SLUP structure. If the 'frame' is not 0x00 and the 'receive'
 * function pointer in the SLUP structure is valid, it calls the 'receive' function to handle
 * the received data in the 'buffer' with the specified size 'bsize'.
 */
static int slup_receive_package(SLUP *slup)
{
    if (slup->parser.frame == 0x00)
    {
        uint8_t link = 0;

        link = slup->buffer[0];

        if (link & SLUP_LINK_RX)
        {
            slup->link |= SLUP_LINK_TX;
        }
        else  
        {
            slup->link &= (~SLUP_LINK_TX);
        }
    }
    else
    {
        if (slup->receive) 
        {
            (slup->receive)(slup->buffer, slup->bsize);
        }
    }
    return SLUP_E_OK;
}

/**
 * \brief Send an SLUP package.
 * \param slup: Pointer to the SLUP structure.
 * \param frame: The frame type of the package.
 * \param data: Pointer to the data buffer of the package.
 * \param length: The length of the data in the package.
 * \return SLUP_E_OK: Indicates that the package has been successfully sent.
 *         SLUP_E_INVALID: Returned if the 'slup' pointer is NULL.
 *         SLUP_E_DATA: Returned if the 'data' pointer is NULL.
 *         SLUP_E_LEN: Returned if the 'length' is 0.
 * 
 * This function constructs and sends an SLUP package. It first validates the input parameters.
 * Then it sends each part of the package in order: the head, sequence number (SN), frame type,
 * data length, data, checksum, and tail. The sequence number is incremented after being sent.
 * The checksum is calculated using the 'check' function pointer in the SLUP structure.
 */
static int slup_send_package(SLUP *slup, uint8_t frame, uint8_t *data, uint16_t length)
{
    uint32_t i = 0;
    uint32_t check = 0;

    if (!slup) return SLUP_E_INVALID;
    if (!data) return SLUP_E_DATA;
    if (length == 0) return SLUP_E_LEN; 

    /* Send the HEAD part of the package */
    for (i = 0; i < slup->cfg.hsize; i++)
    {
        sputc(head(i));
    }

    /* Send the SN (Sequence Number) part of the package */
    sputc(sn(0));
    sputc(sn(1));
    sputc(sn(2));
    sputc(sn(3));
    slup->sn++;

    /* Send the FrameType part of the package */
    sputc(frame);

    /* Send the Length part of the package */
    sputc(len(0));
    sputc(len(1));

    /* Calculate the checksum of the data */
    check = (slup->check)(data, length);

    /* Send the Data part of the package */
    for (i = 0; i < length; i++)
    {
        sputc(data[i]);
    }

    /* Send the Check part of the package */
    for (i = 0; i < slup->cfg.csize; i++)
    {
        sputc((((uint8_t *)(&(check)))[(i)]));
    }

    /* Send the TAIL part of the package */
    for (i = 0; i < slup->cfg.tsize; i++)
    {
        sputc(tail(i));
    }

    return SLUP_E_OK;
}

/**
 * \brief Parses the received data in the SLUP queue and processes it according to the SLUP protocol.
 * \param slup: Pointer to the SLUP structure.
 * 
 * This function is responsible for parsing the data in the SLUP queue. It iterates through all the
 * data in the queue when there is data available. For each byte of data, it uses a state machine
 * (implemented with a switch statement) to process the data based on the current state of the parser.
 * The states represent different parts of the SLUP package such as the head, sequence number (SN),
 * frame type, length, data, checksum, and tail. Once a complete package is parsed and verified,
 * it calls the slup_receive_package function to handle the received package and resets the buffer
 * and parser state for the next package.
 */
static void slup_parse_task(SLUP *slup)
{
    uint32_t i = 0;
    char data = 0;

    if (slup->queue.size > 0)
    {
        for (i = 0; i < slup->queue.size; i++)
        {
            data = slup_queue_at(&slup->queue, i);

            SLUP_DEBUG("%02x ", data);

            switch (slup->parser.state)
            {
            case SLUP_RX_STATE_HEAD:
            {
                // If the current index for the head (hindex) is less than the configured head size
                if (slup->parser.hindex < slup->cfg.hsize)
                {
                    // If the received data byte matches the expected head byte at the current index
                    if (data == slup->cfg.head[slup->parser.hindex])
                    {
                        // Increment the head index
                        slup->parser.hindex++;

                        // If the head index reaches the configured head size, it means the head is fully received
                        if (slup->parser.hindex == slup->cfg.hsize)
                        {
                            slup->parser.hindex = 0;
                            SLUP_DEBUG(" [SLUP_RX_STATE_HEAD] OK\r\n");
                            // Move to the next state which is to receive the sequence number (SN)
                            slup->parser.state = SLUP_RX_STATE_SN;
                        }
                    }
                    else  
                    {
                        // If the received byte doesn't match, reset the head index
                        slup->parser.hindex = 0;
                    }
                }
                else  
                {

                }
            } break;
            case SLUP_RX_STATE_SN:
            {
                // If the current index for the sequence number (sindex) is less than the configured SN size
                if (slup->parser.sindex < slup->cfg.ssize)
                {
                    // Store the received data byte into the appropriate position of the parser's SN
                    ((uint8_t *)(&(slup->parser.sn)))[slup->parser.sindex] = data;

                    // Increment the sequence number index
                    slup->parser.sindex++;

                    // If the sequence number index reaches the configured SN size, it means the SN is fully received
                    if (slup->parser.sindex == slup->cfg.ssize)
                    {
                        slup->parser.sindex = 0;
                        SLUP_DEBUG(" [SLUP_RX_STATE_SN] OK\r\n");
                        // Move to the next state which is to receive the frame type
                        slup->parser.state = SLUP_RX_STATE_FRAMETYPE;
                    }
                }
                else  
                {

                }
            } break;
            case SLUP_RX_STATE_FRAMETYPE:
            {
                // Store the received data byte as the frame type
                slup->parser.frame = data;
                SLUP_DEBUG(" [SLUP_RX_STATE_FRAMETYPE] OK\r\n");
                // Move to the next state which is to receive the length
                slup->parser.state = SLUP_RX_STATE_LENGTH;
            } break;
            case SLUP_RX_STATE_LENGTH:
            {
                // If the current index for the length (lindex) is less than the size of a uint16_t (since length is uint16_t)
                if (slup->parser.lindex < sizeof(uint16_t))
                {
                    // Store the received data byte into the appropriate position of the parser's length
                    ((uint8_t *)(&(slup->parser.length)))[slup->parser.lindex] = data;

                    // Increment the length index
                    slup->parser.lindex++;

                    // If the length index reaches the size of a uint16_t, it means the length is fully received
                    if (slup->parser.lindex == sizeof(uint16_t))
                    {
                        slup->parser.lindex = 0;
                        SLUP_DEBUG(" [SLUP_RX_STATE_LENGTH] OK\r\n");
                        // Move to the next state which is to receive the data
                        slup->parser.state = SLUP_RX_STATE_DATA;
                    }
                }
                else  
                {

                }
            } break;
            case SLUP_RX_STATE_DATA:
            {
                // Store the received data byte into the buffer and increment the buffer size
                slup->buffer[slup->bsize++] = data;
                // If the current index for the data (dindex) is less than the received length
                if (slup->parser.dindex < slup->parser.length)
                {
                    // Increment the data index
                    slup->parser.dindex++;

                    // If the data index reaches the received length, it means the data is fully received
                    if (slup->parser.dindex == slup->parser.length)
                    {
                        slup->parser.dindex = 0;
                        SLUP_DEBUG(" [SLUP_RX_STATE_DATA] OK\r\n");
                        // Move to the next state which is to receive the checksum
                        slup->parser.state = SLUP_RX_STATE_CHECK;
                    }
                }
                else  
                {

                }
            } break;
            case SLUP_RX_STATE_CHECK:
            {
                // If the current index for the checksum (cindex) is less than the configured checksum size
                if (slup->parser.cindex < slup->cfg.csize)
                {
                    // Store the received data byte into the appropriate position of the parser's checksum
                    ((uint8_t *)(&(slup->parser.check)))[slup->parser.cindex] = data;

                    // Increment the checksum index
                    slup->parser.cindex++;

                    // If the checksum index reaches the configured checksum size, it means the checksum is fully received
                    if (slup->parser.cindex == slup->cfg.csize)
                    {
                        slup->parser.cindex = 0;

                        uint32_t cvalue = 0;

                        // Calculate the checksum of the received data in the buffer
                        cvalue = (slup->check)(slup->buffer, slup->bsize);

                        // Compare the calculated checksum with the received checksum
                        if (memcmp(&cvalue, &slup->parser.check, slup->cfg.csize) == 0)
                        {
                            SLUP_DEBUG(" [SLUP_RX_STATE_CHECK] OK\r\n");
                            // Move to the next state which is to receive the tail
                            slup->parser.state = SLUP_RX_STATE_TAIL;
                        }
                        else  
                        {
                            // If the checksums don't match, reset the buffer size for the next reception
                            slup->bsize = 0; 
                            // Reset the parser state to start receiving a new package from the head
                            slup->parser.state = SLUP_RX_STATE_HEAD;
                        }
                    }
                }
                else  
                {

                }
            } break;
            case SLUP_RX_STATE_TAIL:
            {
                // If the current index for the tail (tindex) is less than the configured tail size
                if (slup->parser.tindex < slup->cfg.tsize)
                {
                    // If the received data byte matches the expected tail byte at the current index
                    if (data == slup->cfg.tail[slup->parser.tindex])
                    {
                        // Increment the tail index
                        slup->parser.tindex++;

                        // If the tail index reaches the configured tail size, it means the tail is fully received
                        if (slup->parser.tindex == slup->cfg.tsize)
                        {
                            slup->parser.tindex = 0;
                            SLUP_DEBUG(" [SLUP_RX_STATE_TAIL] OK\r\n");
                            // Call the function to handle the received package
                            slup_receive_package(slup);
                            // Reset the buffer size for the next reception
                            slup->bsize = 0;
                            // Reset the parser state to start receiving a new package from the head
                            slup->parser.state = SLUP_RX_STATE_HEAD;
                        }
                    }
                    else  
                    {
                        // If the received byte doesn't match, reset the tail index and the parser state to start from the head
                        slup->parser.tindex = 0;
                        slup->parser.state = SLUP_RX_STATE_HEAD;
                    }
                }
                else  
                {

                }
            } break;
            default:
                break;
            }
        }

        // Pop all the data from the queue after processing
        slup_queue_pop(&slup->queue, 0xFFFFF);
    }
}

/**
 * \brief Calculate the upload and download rates and reset the bit counters.
 * \param slup: Pointer to the SLUP structure.
 * 
 * This function is responsible for calculating the upload and download rates.
 * It copies the current values of 'upbits' and 'downbits' to 'uprate' and 'downrate' respectively.
 * Then it resets 'upbits' and 'downbits' to zero, preparing for the next rate calculation.
 */
static void slup_calrate_task(SLUP *slup)
{
    slup->uprate = slup->upbits;
    slup->downrate = slup->downbits;
    slup->upbits = 0;
    slup->downbits = 0;
}

/**
 * \brief Update the dummy data parameters based on the upload rate.
 * \param slup: Pointer to the SLUP structure.
 * 
 * This function updates the 'gapcount', 'gapbase', 'compression', and 'rate' fields
 * in the 'dummy' structure of the SLUP object. It first calculates the deviation
 * between the upload rate and the target rate. If the upload rate is less than the target,
 * it increases the 'gapcount' by a fixed resolution value. If the upload rate is greater
 * than the target, it decreases the 'gapcount' by the same resolution value.
 * Then it calculates the 'gapbase' as the integer part of 'gapcount' divided by 100,
 * and the 'compression' as the fractional part of 'gapcount' divided by 100 minus 'gapbase'.
 * Finally, it sets the 'rate' to the 'compression' value.
 */
static void slup_dummy_update(SLUP *slup)
{
    const uint32_t resolution = 5;

    /* Update the deviation value and record it in 'slup->dummy.gapcount' */
    if (slup->uprate < slup->dummy.target)
    {
        if (slup->dummy.gapcount + resolution > slup->dummy.gapcount)
        {
            slup->dummy.gapcount += resolution;
        }
    }
    else if (slup->uprate > slup->dummy.target)
    {
        if (slup->dummy.gapcount >= resolution)
        {
            slup->dummy.gapcount -= resolution;
        }
    }

    /* Update the basic sending number and compression rate of the sending point */
    slup->dummy.gapbase = (uint32_t)(slup->dummy.gapcount / 100);
    slup->dummy.compression = (double)slup->dummy.gapcount / 100.0 - slup->dummy.gapbase;
    slup->dummy.rate = slup->dummy.compression;
}

/**
 * \brief Execute the dummy data sending process based on the calculated parameters.
 * \param slup: Pointer to the SLUP structure.
 * 
 * This function calculates the number of messages to send based on the 'gapbase'
 * and 'compression' values in the 'dummy' structure of the SLUP object. It adds the
 * 'compression' value to the 'rate'. If the 'rate' exceeds 1.0, it subtracts 1.0 from
 * the 'rate' and increments the number of messages to send.
 * If there are messages to send, it calls the 'slup_send' function to send the dummy data
 * in the 'dummy' structure 'send' times.
 */
static void slup_dummy_execute(SLUP *slup)
{
    uint32_t send = 0;

    /* Calculate how many messages the current sending point needs to send */
    send = slup->dummy.gapbase;
    slup->dummy.rate += slup->dummy.compression;
    if (slup->dummy.rate > 1.0)
    {
        slup->dummy.rate -= 1.0;
        send++;
    }

    /* Evenly 'gapCount' the difference to each sending point for sending */
    if (send > 0)
    {
        for (int i = 0; i < send; i++)
        {
            slup_send(slup, slup->dummy.data, sizeof(slup->dummy.data));
        }
    }
}

/**
 * \brief Sends a heartbeat message in the SLUP protocol.
 * \param slup: Pointer to the SLUP structure.
 * \return SLUP_E_OK if the message is successfully sent, appropriate error code otherwise.
 * 
 * This function constructs a heartbeat message. It sets the first byte of the data buffer
 * to the current link status from the SLUP structure. Then it calls the slup_send_package
 * function with a frame type of 0x00 to send the message.
 */
static int slup_send_heart(SLUP *slup)
{
    uint8_t data[SLUP_SN_MAX];
    uint16_t length = 0;

    data[0] = slup->link;

    length = 1;

    return slup_send_package(slup, 0x00, data, length);
}

/**
 * \brief Initializes the SLUP structure.
 * \param slup: Pointer to the SLUP structure.
 * \return SLUP_E_OK if the initialization is successful, SLUP_E_INVALID if the pointer is NULL.
 * 
 * This function initializes various fields in the SLUP structure. It sets the buffer size (bsize),
 * sequence number (sn), and timestamp to 0. It also initializes the queue's head, tail, and size to 0,
 * and clears the parser structure using memset.
 */
int slup_init(SLUP *slup)
{
    if (!slup) return SLUP_E_INVALID;

    // memset(slup, 0, sizeof(SLUP));

    slup->bsize = 0;
    slup->sn = 0;
    slup->timestamp = 0;

    /* Init queue */
    slup->queue.head = 0;
    slup->queue.tail = 0;
    slup->queue.size = 0;

    /* Init parser */
    memset(&slup->parser, 0, sizeof(SLUP_PARSER));

    return SLUP_E_OK;
}

/**
 * \brief Sends data in the SLUP protocol with a frame type of 0x01.
 * \param slup: Pointer to the SLUP structure.
 * \param data: Pointer to the data buffer to be sent.
 * \param length: The length of the data buffer.
 * \return SLUP_E_OK if the data is successfully sent, appropriate error code otherwise.
 * 
 * This function simply calls the slup_send_package function with a frame type of 0x01
 * to send the provided data.
 */
int slup_send(SLUP *slup, uint8_t *data, uint16_t length)
{
    return slup_send_package(slup, 0x01, data, length);
}

/**
 * \brief Handles the reception of a single character in the SLUP system.
 * \param slup: Pointer to the SLUP structure.
 * \param c: The received character.
 * 
 * This function updates the link status to indicate a received character (sets SLUP_LINK_RX),
 * clears the silent flag, updates the download statistics, and pushes the received character
 * into the queue.
 */
void slup_getc(SLUP *slup, char c)
{
    if (!slup) return;

    slup->link |= SLUP_LINK_RX;
    slup->silent = 0;

    slup_statis_download(slup);
    
    slup_queue_push(&slup->queue, c);
}

/**
 * \brief Retrieves the current link status from the SLUP structure.
 * \param slup: Pointer to the SLUP structure.
 * \param link: Pointer to a variable where the link status will be stored.
 * \return SLUP_E_OK if the retrieval is successful, appropriate error code otherwise.
 * 
 * This function checks if the provided pointers are valid. If so, it copies the current
 * link status from the SLUP structure to the provided variable.
 */
int slup_link_status(SLUP *slup, uint8_t *link)
{
    if (!slup) return SLUP_E_INVALID;
    if (!link) return SLUP_E_LINK;

    *link = slup->link;

    return SLUP_E_OK;
}

/**
 * \brief Retrieves the upload rate from the SLUP structure.
 * \param slup: Pointer to the SLUP structure.
 * \param rate: Pointer to a variable where the upload rate will be stored.
 * \return SLUP_E_OK if the retrieval is successful, appropriate error code otherwise.
 * 
 * This function checks if the provided pointers are valid. If so, it copies the current
 * upload rate from the SLUP structure to the provided variable.
 */
int slup_upload_rate(SLUP *slup, uint32_t *rate)
{
    if (!slup) return SLUP_E_INVALID;
    if (!rate) return SLUP_E_RATE;

    *rate = slup->uprate;

    return SLUP_E_OK;
}

/**
 * \brief Retrieves the download rate from the SLUP structure.
 * \param slup: Pointer to the SLUP structure.
 * \param rate: Pointer to a variable where the download rate will be stored.
 * \return SLUP_E_OK if the retrieval is successful, appropriate error code otherwise.
 * 
 * This function checks if the provided pointers are valid. If so, it copies the current
 * download rate from the SLUP structure to the provided variable.
 */
int slup_download_rate(SLUP *slup, uint32_t *rate)
{
    if (!slup) return SLUP_E_INVALID;
    if (!rate) return SLUP_E_RATE;

    *rate = slup->downrate;

    return SLUP_E_OK;
}

/**
 * \brief Sets the target rate for the dummy data in the SLUP structure.
 * \param slup: Pointer to the SLUP structure.
 * \param rate: The target rate value to be set.
 * \return SLUP_E_OK if the setting is successful, SLUP_E_INVALID if the pointer is NULL.
 * 
 * This function checks if the provided pointer is valid. If so, it sets the target rate
 * in the dummy data part of the SLUP structure to the provided value.
 */
int slup_set_dummy(SLUP *slup, uint32_t rate)
{
    if (!slup) return SLUP_E_INVALID;

    slup->dummy.target = rate;

    return SLUP_E_OK;
}

/**
 * \brief The main task function for the SLUP system.
 * \param slup: Pointer to the SLUP structure.
 * 
 * This function is the main task handler for the SLUP system. It updates the timestamp,
 * and based on the timestamp value, performs various operations such as sending heartbeat
 * messages, calculating rates, executing dummy data sending, and updating dummy data parameters.
 * It also calls the slup_parse_task function to parse the received data in the queue.
 */
void slup_task(SLUP *slup)
{
    if (!slup) return;

    slup->timestamp += slup->period;
    if (slup->timestamp >= 252000000) slup->timestamp = 0;

    if (slup->timestamp % 500 == 0)
    {
        if (slup->silent < 3)
        {
            slup->silent++;
        }
        else  
        {
            slup->link &= (~SLUP_LINK_RX);
        }

        slup_send_heart(slup);
    }

    if (slup->timestamp % 1000 == 0)
    {
        slup_calrate_task(slup);
    }

    if (slup->timestamp % 10 == 0)
    {
        slup_dummy_execute(slup);
    }

    if (slup->timestamp % 1000 == 0)
    {
        slup_dummy_update(slup);
    }

    slup_parse_task(slup);
}

